using System.Collections.Generic;
using Audio;
using Framework.Timer;
using UnityEngine;

namespace Framework.Audio
{
    /// <summary>
    /// @Foldcc
    /// 基于通用音频管理器派生而来，针对该项目的使用需求改进部分api和逻辑
    /// </summary>
    public class AudioManager : BaseAudioManager
    {

        #region 单例声明

        private static AudioManager _instance;

        public static AudioManager Instance
        {
            get
            {
                if (_instance != null) return _instance;
                var obj = new GameObject {name = "[ AudioManager ]"};
                DontDestroyOnLoad(obj);
                _instance = obj.AddComponent<AudioManager>();
                //_instance.Init(new AudioSourceHandler(_AUDIO_Path));
                return _instance;
            }
        }

        #endregion

        private static readonly string _MUSIC_VALUE = "MusicValue";
        private static readonly string _SOUND_VALUE = "SoundValue";
        public static readonly string _AUDIO_Path  = "Audio";

        /// <summary>
        /// 用于debug数据监视
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> EditorLOG()
        {
#if UNITY_EDITOR
            return this.AudioSourceHandler?.EditorLog();
#else
            return null;
#endif
        }

        public Dictionary<string, string> CacheMusic;

        public float SoundValue
        {
            get => this._localSoundVolume;
            set
            {
                this._localSoundVolume = value;
                this.SetGroupVolume(AudioType.SOUND, value);
            }
        }

        public float MusicValue
        {
            get => this._localMusicVolume;
            set
            {
                this._localMusicVolume = value;
                this.SetGroupVolume(AudioType.BGM, value);
            }
        }

        public float BSEValue 
        {
            get => this._localBSEVolume;
            set
            {
                this._localBSEVolume = value;
                this.SetGroupVolume(AudioType.BSE, value);
            }
        }

        private float _localMusicVolume;
        private float _localSoundVolume;
        private float _localBSEVolume;

        private TimeHandler _curTimeHandler;
        /// <summary>
        /// 初始化音频管理器
        /// </summary>
        public override void Init(IAudioSourceHandler audioSourceHandler)
        {
            this.AudioSourceHandler = audioSourceHandler;
            this.CacheMusic         = new Dictionary<string, string>();
            //设置该项目下音频资源的根目录
            this.SetSourcePath(_AUDIO_Path);
            //初始化音频资源加载器
            //初始化音量
            this.LoadVolume();
            // 提前缓存部分音轨，若游戏中同时播放很多音轨会自动增加额外音轨，这里的作用类似对象池预先缓存资源
            this._AudioFree.Add(this.CreateAudio((ushort) AudioType.BGM));
            this._AudioFree.Add(this.CreateAudio((ushort) AudioType.BSE));
            this._AudioFree.Add(this.CreateAudio((ushort) AudioType.BSE));
            this._AudioFree.Add(this.CreateAudio((ushort) AudioType.BSE));
            this._AudioFree.Add(this.CreateAudio((ushort) AudioType.SOUND));
            this._AudioFree.Add(this.CreateAudio((ushort) AudioType.SOUND));
            this._AudioFree.Add(this.CreateAudio((ushort) AudioType.SOUND));
            //（重要）挂载Update 到 GameUpdaterMgr中，用于回收音频资源以及音频播放的Update
            GameUpdateMgr.Instance.AddUpdater(this.DoUpdate);
        }

        public bool InitHook() { return true; }
        

        #region 音频信息存储

        /// <summary>
        /// 存储当前各组音轨的音量设置
        /// </summary>
        public virtual void SaveVolume()
        {
            AudioSourceHandler.SaveVolume(MusicValue, BSEValue, SoundValue);
        }

        /// <summary>
        /// 读取本地音量设置
        /// </summary>
        public virtual void LoadVolume()
        {
            var volumes = AudioSourceHandler.LoadVolume();
            this.MusicValue = volumes[0];
            this.BSEValue = volumes[1];
            this.SoundValue = volumes[2];
        }

        #endregion

        #region 通用音频控制API

        /// <summary>
        /// 卸载所有0引用的音频资源
        /// </summary>
        public void UnLoadAllInvalid() { (this.AudioSourceHandler).UnLoadAllInvalid(); }
        
        /// <summary>
        /// 获取bgm的音轨
        /// </summary>
        /// <returns></returns>
        public AudioTrack GetBGM()
        {
            var tracks = this.GetPlayingAudio((ushort) AudioType.BGM);
            if (tracks?.Count > 0)
            {
                return tracks[0];
            }
            return null;
        }


        /// <summary>
        /// 用于播放背景音乐做特殊处理， 背景音乐只限制为一条音轨，如果新的背景音乐和当前相同，则继续播放，反之覆盖播放
        /// </summary>
        /// <param name="audioName"></param>
        /// <param name="volume"></param>
        /// <param name="inTime"></param>
        /// <param name="isLoop"></param>
        /// <returns></returns>
        public AudioTrack PlayBGM(string audioName, float volume = 1, float inTime = 0, bool isLoop = true)
        {
            var tracks = this.GetPlayingAudio((ushort) AudioType.BGM);
            if (tracks?.Count > 0)
            {
                if (audioName == tracks[0].AudioName)
                {
                    tracks[0].UnPause(inTime);
                    return tracks[0];
                }
                else
                {
                    tracks[0].Kill();
                }
            }

            if (audioName != null)
            {
                return this.BasePlay(audioName, volume, 0, inTime, (ushort) AudioType.BGM, isLoop);
            }

            return null;
        }

        public AudioTrack PlayBSE(string audioName, float volume = 1, float inTime = 0, bool isLoop = true) { return this.BasePlay(audioName, volume, 0, inTime, AudioType.BSE, isLoop); }

        public AudioTrack PlaySound(string audioName, float volume = 1, float inTime = 0, bool isLoop = false) { return this.BasePlay(audioName, volume, 0, inTime, AudioType.SOUND, isLoop); }

        public AudioTrack PlaySound3D(string audioName, Vector3 worldPosition, float volume = 1, float inTime = 0, bool isLoop = false)
        {
            var track = this.BasePlay(audioName, volume, 1, inTime,  AudioType.SOUND, isLoop);
            if (track != null)
            {
                track.transform.position = worldPosition;
            }

            return track;
        }

        public AudioTrack PlayBSE3D(string audioName, Vector3 worldPosition, float volume = 1, float inTime = 0, bool isLoop = false)
        {
            var track = this.BasePlay(audioName, volume, 1, inTime,  AudioType.BSE, isLoop);
            if (track != null)
                track.transform.position = worldPosition;
            return track;
        }

        #endregion

    }
}